#ifndef GMatrix_DEFINED
#define GMatrix_DEFINED

#include <stdlib.h>
#include <math.h>

#include "GTypes.h"
#include "GRect.h"
#include "GPoint.h"

///////////////////////////////////////////////////////////////////////////////
// GVector Class
//
// 3x1 homogenized vector class
 class GVector{
public:
 	float fX, fY, fZ;
 	
 	GVector(){
 		fX = 0.0f;
 		fY = 0.0f;
 		fZ = 1.0f;
 	} 	
 	GVector(float x, float y){
 		fX = x;
 		fY = y;
 		fZ = 1.0f;
 	}
 	GVector(float x, float y, float z){
 		fX = x;
 		fY = y;
 		fZ = z;
 	}
 	GVector(GPoint p){
 		fX = p.fX;
 		fY = p.fY;
 		fZ = 1.0f;
 	}

 	// dot product of vectors
 	static float dot(const GVector& v1, const GVector& v2);

 };

///////////////////////////////////////////////////////////////////////////////
// GMatrix Class
//
// Column-ordered 3x3 homogenized matrix for rotation, scale and translation
class GMatrix{
public:
	GVector row1, row2;  // Row Vectors to represent matrix

	//set to identity
	GMatrix(){
		row1 = GVector(1.0f, 0.0f, 0.0f);
		row2 = GVector(0.0f, 1.0f, 0.0f);
		}
	GMatrix(float m11, float m12, float m13,
		    float m21, float m22, float m23){
		row1 = GVector(m11, m12, m13);
		row2 = GVector(m21, m22, m23);
		}

	void print() const { // debugging purposes
		printf("Matrix:\n %f, %f, %f\n %f, %f, %f\n", 
			row1.fX, row1.fY, row1.fZ,
			row2.fX, row2.fY, row2.fZ);
	}

	float det() const {
		return row1.fX * row2.fY - row1.fY * row2.fX;
	}

	void precat(const GMatrix& M);
	GMatrix inverse() const;
	GVector transform(const GVector& v) const;

	GPoint toDeviceCoords(const GPoint& p) const;
	GPoint xformPoint(const GPoint& p) const;
	GRect xformRect(const GRect& rect) const;

	static GMatrix multiply(const GMatrix& m1, const GMatrix& m2);
	static GMatrix scale(float x, float y);
	static GMatrix translate(float x, float y);
};

#endif